/**************************************************************************

Copyright: sherlock
Author: sherlock
Date: 2021-2-28
Description: encapsulation base in libuv tcp client

**************************************************************************/

#ifndef TCP_SOCKET_H
#define TCP_SOCKET_H

#include "header.h"

class TcpSocketPrivateData;

class TcpSocket
{
public:
    static void exec();
public:
    TcpSocket();
    explicit TcpSocket(uv_tcp_t *clientSocket);
    virtual ~TcpSocket();

    /**
     * @brief:  设置事件循环
     * @author: sherlock
     */
    void setEventLoop(uv_loop_t *loop);
    uv_loop_t *getLoop() const;

    /**
     * @brief:  设置/获取IP地址
     * @author: sherlock
     */
    void setIPAddress(const std::string &ip);

    std::string getIpAddress() const;

    /**
     * @brief:  设置/获取服务端的端口
     * @author: sherlock
     */
    void setPort(int port);
    int getPort() const;

    std::string peerIp() const;

    int peerPort() const;

    /**
     * @brief: 连接主机
     * @return: 是否成功
     * @note: 返回值只表示连接动作是否执行成功，并不能表示是否连接成功，若需要知道是否连接成功，则必须重写onConnect()方法
     * @author: sherlock
     */
    bool connectToHost();

    /**
     * @brief:  关闭连接
     * @author: sherlock
     */
    void close();

    std::string getIpAddr() const;

    /**
     * @brief:  获取最近一次错误描述
     * @author: sherlock
     */
    std::string getLastErrorMessage() const;

    /**
     * @brief:  根据错误码获取错误描述
     * @author: sherlock
     */
    static std::string getErrorMessage(int errorCode);

public:
    /**
     * @brief:  连接主机之后执行，可重写后自定义处理，也可以设置回调函数处理
     * @param:  status表示是否连接
     * @author: sherlock
     */
    virtual void onConnect(bool status);

    typedef void (*OnConnect)(bool status, void *userData);

    /**
     * @brief:  设置主机连接后执行的回调
     * @author: sherlock
     */
    void setOnConnectCB(OnConnect onConnect, void *userData);

    /**
     * @brief:  正常读取数据，可重写后自定义处理，也可以设置回调函数处理
     * @author: sherlock
     */
    virtual void read(const char *buf, size_t size);

    typedef void (*OnRead)(const char *buf, size_t size, void *userData);

    /**
     * @brief:  设置正常读取数据回调
     * @author: sherlock
     */
    void setOnReadCB(OnRead onRead, void *userData);

    /**
     * @brief:  读取数据错误后执行，errorMessage为错误描述，可重写后自定义处理，也可以设置回调函数处理
     * @author: sherlock
     */
    virtual void readError(const char *errorMessage);

    typedef void (*OnReadError)(const char *errorMessage, void *userData);

    /**
     * @brief:  设置读取数据错误后执行的回调函数
     * @author: sherlock
     */
    void setReadErrorCB(OnReadError readError, void *userData);

    /**
     * @brief:  连接关闭后执行，可重写后自定义处理，也可以设置回调函数处理
     * @author: sherlock
     */
    virtual void onClose();

    typedef void (*OnClose)(void *userData);

    /**
     * @brief:  设置关闭后执行的回调函数
     * @author: sherlock
     */
    void setOnCloseCB(OnClose onClose, void *userData);

    /**
     * @brief:  连接断开后执行，可重写后自定义处理，也可以设置回调函数处理
     * @author: sherlock
     */
    virtual void disconnected();

    typedef void (*OnDisconnected)(void *userData);

    /**
     * @brief:  设置连接断后后执行的回调函数
     * @author: sherlock
     */
    void setDisconnectedCB(OnDisconnected disconnected, void *userData);

private:
    /**
     * @brief:  初始化数据
     * @author: sherlock
     */
    void initializeData();

private:
    /**
     * @brief:  连接成功后执行，自定调用，勿改动
     * @author: sherlock
     */
    static void onConnectCB(uv_connect_t *req, int status);

    /**
     * @brief:  读取数据前分配资源，自定调用，勿改动
     * @author: sherlock
     */
    static void allocBufferCB(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf);

    /**
     * @brief:  读取数据回调，自定调用，勿改动
     * @author: sherlock
     */
    static void readCB(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf);

    /**
     * @brief:  关闭连接后回调，自定调用，勿改动
     * @author: sherlock
     */
    static void onCloseCB(uv_handle_t *handle);

protected:
    std::unique_ptr<TcpSocketPrivateData> data;
};

#endif //TCP_SOCKET_H
